package com.msb.serviceorder.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.msb.internalcommon.constant.CommonStatusEnum;
import com.msb.internalcommon.constant.IdentityConstant;
import com.msb.internalcommon.constant.OrderConstants;
import com.msb.internalcommon.dto.Car;
import com.msb.internalcommon.dto.OrderInfo;
import com.msb.internalcommon.dto.PriceRule;
import com.msb.internalcommon.dto.ResponseResult;
import com.msb.internalcommon.reponese.OrderDriverResponse;
import com.msb.internalcommon.reponese.TerminalResponse;
import com.msb.internalcommon.request.OrderRequest;
import com.msb.internalcommon.util.RedisPrefixUtils;
import com.msb.serviceorder.mapper.OrderInfoMapper;
import com.msb.serviceorder.remote.ServiceDriverUserClient;
import com.msb.serviceorder.remote.ServiceMapClient;
import com.msb.serviceorder.remote.ServicePriceClient;
import com.msb.serviceorder.remote.ServiceSeePushClient;
import com.mysql.cj.Query;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.omg.CosNaming.IstringHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.xml.ws.Response;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务类
 * </p>
 *
 * @author jiudianliu
 * @since 2023-07-17
 */
@Service
@Slf4j
public class OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper ;

    @Autowired
    ServicePriceClient servicePriceClient;

    @Autowired
    ServiceDriverUserClient serviceDriverUserClient;

    @Autowired
    ServiceMapClient serviceMapClient ;

    @Autowired
    StringRedisTemplate stringRedisTemplate ;

    @Autowired
    ServiceSeePushClient serviceSeePushClient ;


    public ResponseResult add(OrderRequest orderRequest) {

        //  查看当前城市是否有无可用的司机
        ResponseResult<Boolean> availableDriver = serviceDriverUserClient.isAvailableDriver(orderRequest.getAddress());
        log.info("测试当前城市是否有可用司机" + availableDriver.getData());
        if ( ! availableDriver.getData()){
            return ResponseResult.fail(CommonStatusEnum.CITY_DRIVER_EMPTY.getCode() , CommonStatusEnum.CITY_DRIVER_EMPTY.getValue());
        }


        // 判断  下单的设备是否是黑名单设备
        if (isBlackDevice(orderRequest))
            return ResponseResult.fail(CommonStatusEnum.DEVICE_IS_BLACK.getCode(), CommonStatusEnum.DEVICE_IS_BLACK.getValue());

        // 判断 乘客 是否有在进行的订单，如果有不可重复下单
        if (isPassengerOrderGoingon(orderRequest.getPassengerId()) > 0) {
            return ResponseResult.fail(CommonStatusEnum.ORDER_GOING_ON.getCode(), CommonStatusEnum.ORDER_GOING_ON.getValue());
        }

        //  判断  下单的城市和计价规则是否正常
        if (!isPriceRuleExists(orderRequest)){
            return ResponseResult.fail(CommonStatusEnum.CITY_SERVICE_NOT_SERVICE.getCode() , CommonStatusEnum.CITY_SERVICE_NOT_SERVICE.getValue());
        }

        OrderInfo orderInfo = new OrderInfo();

        BeanUtils.copyProperties(orderRequest , orderInfo);

        orderInfo.setOrderStatus(OrderConstants.DRIVER_START);

        LocalDateTime now = LocalDateTime.now();

        orderInfo.setGmtCreate(now);

        orderInfo.setGmtModified(now);

        orderInfoMapper.insert(orderInfo);

        // 派单 dispatchRealTimeOrder
        dispatchRealTimeOrder(orderInfo);

        return ResponseResult.success();

    }


    /**
     * 实时订单派单逻辑
     * @param orderInfo
     */
    public synchronized void dispatchRealTimeOrder(OrderInfo orderInfo){
        // 获取经度
        String depLongitude = orderInfo.getDepLongitude();
        // 获取纬度
        String depLatitude = orderInfo.getDepLatitude();
        // 纬度在前，经度在后
        String center = depLatitude + "," + depLongitude;

        List<Integer> radiusList = new ArrayList<>();
        radiusList.add(2000);
        radiusList.add(4000);
        radiusList.add(5000);

        ResponseResult<List<TerminalResponse>> terminalResponseResponseResult = null ;
        for (int i = 0 ; i < radiusList.size() ; i++){
            Integer radius = radiusList.get(i);
            terminalResponseResponseResult = serviceMapClient.terminalAroundSearch(center , radius);

            log.info("在半径为" + radius + "的范围内,寻找车辆,结果" + JSONArray.fromObject(terminalResponseResponseResult.getData()).toString());

            // 获得终端 [{"carId":1679423637933031425,"tid":"726731023"}]

            // 解析终端
            List<TerminalResponse> data = terminalResponseResponseResult.getData();
            for (int j = 0 ; j < data.size() ; j++){
                TerminalResponse terminalResponse = data.get(j);
                Long carId = terminalResponse.getCarId();

                String latitude = terminalResponse.getLatitude();
                String longitude = terminalResponse.getLongitude();

                // 查询是否有对于该城市的可派单司机
                ResponseResult<OrderDriverResponse> availableDriver = serviceDriverUserClient.getAvailableDriver(carId);
                if (availableDriver.getCode() == CommonStatusEnum.AVAILABLE_DRIVER_EMPTY.getCode()){
                    log.info("没有车辆ID" + carId + ",对于的司机");
                    continue;
                }else{
                    log.info("找到了正在出车的司机，它的车辆ID：" + carId);
                    OrderDriverResponse data1 = availableDriver.getData();
                    Long driverId = data1.getDriverId();
                    String driverPhone = data1.getDriverPhone();
                    String licenseId = data1.getLicenseId();
                    String vehicleNo = data1.getVehicleNo();

                    // 判断 乘客 是否有在进行的订单，如果有不可重复下单
                    if (isDriverOrderGoingon(driverId) > 0) {
                        continue;
                    }
                    // 订单直接匹配司机
                    // 查询当前车辆信息
                    QueryWrapper<Car> carQueryWrapper = new QueryWrapper<>();
                    carQueryWrapper.eq("id" , carId);



                    // 查询当前司机信息
                    orderInfo.setDriverId(driverId);
                    orderInfo.setDriverPhone(driverPhone);
                    orderInfo.setCarId(carId);
                    // 地图中获取
                    orderInfo.setReceiveOrderCarLongitude(longitude );
                    orderInfo.setReceiveOrderCarLatitude(latitude );

                    orderInfo.setReceiveOrderTime(LocalDateTime.now());
                    orderInfo.setLicenseId(licenseId);
                    orderInfo.setVehicleNo(vehicleNo);
                    orderInfo.setOrderStatus(OrderConstants.DRIVER_RECEIVER_ORDER);

                    orderInfoMapper.updateById(orderInfo);

                    // 通知司机
                    JSONObject driverContent = new JSONObject();
                    driverContent.put("passengerId" , orderInfo.getPassengerId());
                    driverContent.put("passengerPhone" , orderInfo.getPassengerPhone());
                    driverContent.put("departure" , orderInfo.getDeparture());
                    driverContent.put("depLongitude" , orderInfo.getDepLongitude());
                    driverContent.put("depLatitude" , orderInfo.getDepLatitude());
                    driverContent.put("destination" , orderInfo.getDestination());
                    driverContent.put("destLongitude" , orderInfo.getDestLongitude());
                    driverContent.put("destLatitude" , orderInfo.getDestLatitude());
                    serviceSeePushClient.push(driverId, IdentityConstant.DRIVER_IDENTITY ,driverContent.toString()) ;

                    // 通知乘客
                    // 通知司机
                    JSONObject passengerContent = new JSONObject();
                    passengerContent.put("driverId" , orderInfo.getDriverId());
                    passengerContent.put("driverPhone" , orderInfo.getDriverPhone());
                    passengerContent.put("vehicleNo" , orderInfo.getVehicleNo());

                    // 车辆信息
                    ResponseResult<Car> carById = serviceDriverUserClient.getCarById(carId);
                    Car carRemote = carById.getData();

                    passengerContent.put("brand" , carRemote.getBrand());
                    passengerContent.put("model" , carRemote.getModel());
                    passengerContent.put("vehicleColor" , carRemote.getVehicleColor());


                    passengerContent.put("receiveOrderCarLongitude" , orderInfo.getReceiveOrderCarLongitude());
                    passengerContent.put("receiveOrderCarLatitude" , orderInfo.getReceiveOrderCarLatitude());

                    serviceSeePushClient.push(orderInfo.getPassengerId(), IdentityConstant.DRIVER_IDENTITY ,passengerContent.toString()) ;

                    break ;
                }

            }
        }
    }


    /**
     * 判断 下单的城市和计价规则是否正常
     */
    private boolean isPriceRuleExists(OrderRequest orderRequest){
        String fareType = orderRequest.getFareType();
        int index = fareType.indexOf("$");
        String cityCode = fareType.substring(0, index);
        String vehicleType = fareType.substring(index + 1);

        PriceRule priceRule = new PriceRule();
        priceRule.setCityCode(cityCode);
        priceRule.setVehicleType(vehicleType);

        ResponseResult<Boolean> booleanResponseResult = servicePriceClient.ifPriceExists(priceRule);

        return booleanResponseResult.getData();
    }

    /**
     *  判断 下单的设备是否为黑名单设备
     * @param
     * @return
     */
    private boolean isBlackDevice(OrderRequest orderRequest) {
        // 判断 下单的设备是否为黑名单设备
        String deviceCode = orderRequest.getDeviceCode();
        // 生成key
        String deviceCodeKey = RedisPrefixUtils.blackDeviceCodePrefix + deviceCode;
        Boolean aBoolean = stringRedisTemplate.hasKey(deviceCodeKey);
        if (aBoolean){
            String s = stringRedisTemplate.opsForValue().get(deviceCodeKey);
            int i = Integer.parseInt(s);
            if (i >= 2){
                // i >= 2 证明当前设备已经超过下单次数
                return true;
            }else
            {
                stringRedisTemplate.opsForValue().increment(deviceCodeKey);
            }
        }else {
            stringRedisTemplate.opsForValue().setIfAbsent(deviceCodeKey , "1" , 1L , TimeUnit.HOURS);
        }
        return false;
    }

    /**
     * 判断 有正在进行的订单不允许下单
     * @param driverId
     * @return
     */
    private int isDriverOrderGoingon(Long driverId){
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("driver_id" , driverId);
        queryWrapper.and(wrapper->wrapper
                .or().eq("order_status" , OrderConstants.DRIVER_RECEIVER_ORDER)
                .or().eq("order_status" , OrderConstants.DRIVER_TO_PICK_UP_PASSENGER)
                .or().eq("order_status" , OrderConstants.DRIVER_ARRIVED_DEPARTURE)
                .or().eq("order_status" , OrderConstants.PICK_UP_PASSENGER));

        Integer validOrderNumber = orderInfoMapper.selectCount(queryWrapper);

        log.info("司机Id:" + driverId + ",正在进行的订单的数量，" + validOrderNumber);

        return validOrderNumber ;
    }
    /**
     * 判断 有正在进行的订单不允许下单
     * @param passengerId
     * @return
     */
    private int isPassengerOrderGoingon(Long passengerId){
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("passenger_id" , passengerId);
        queryWrapper.and(wrapper->wrapper.eq("order_status" , OrderConstants.DRIVER_START)
                .or().eq("order_status" , OrderConstants.DRIVER_RECEIVER_ORDER)
                .or().eq("order_status" , OrderConstants.DRIVER_TO_PICK_UP_PASSENGER)
                .or().eq("order_status" , OrderConstants.DRIVER_ARRIVED_DEPARTURE)
                .or().eq("order_status" , OrderConstants.PICK_UP_PASSENGER)
                .or().eq("order_status" , OrderConstants.PASSENGER_GETOFF)
                .or().eq("order_status" , OrderConstants.TO_START_PAY)
                .or().eq("order_status" , OrderConstants.SUCCESS_PAY));

        Integer validOrderNumber = orderInfoMapper.selectCount(queryWrapper);
        return validOrderNumber ;
    }


}
